﻿
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using Cms.Core.Application.IService;
using Cms.Core.Application.Service.Dto;
using Cms.Core.Data.Model;
using Cms.Core.Infrastructure.Common;
using Cms.Core.Infrastructure.Dependency;
using Cms.Core.Infrastructure.Ui;
using Microsoft.AspNetCore.Http;
using System.Linq;
using System.Security.Claims;
using Newtonsoft.Json;
using Cms.Core.Data.UnitOfWork;
using Cms.Core.Infrastructure.Extension;
using Cms.Core.Infrastructure.Log;
using Cms.Core.Infrastructure.Helps;
using Cms.Core.Infrastructure.Runtime.Session;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using Cms.Core.Application.IService.UserInfo;

namespace Cms.Core.Application.Service
{

    /// <summary>
    /// 异步审核接口
    /// </summary>
    public class AuditService : IAuditService
    {

        private readonly IRepository<AuditLog> _auditLogRepository = null;
        private readonly IWebClientInfoProvider _provider = null;
        private readonly IUnitOfWork _unitOfWork = null;
        private readonly ILoggerHelper _loggerHelper = null;
        private readonly ICmsSession _cmsSession = null;
        private readonly IUserService _userService = null;

      /// <summary>
      /// 
      /// </summary>
      /// <param name="auditLogRepository"></param>
      /// <param name="provider"></param>
      /// <param name="unitOfWor"></param>
      /// <param name="loggerHelper"></param>
      /// <param name="cmsSession"></param>
      /// <param name="userRepository"></param>
      /// <param name="userService"></param>
        public AuditService(IRepository<AuditLog> auditLogRepository, IWebClientInfoProvider provider, IUnitOfWork unitOfWor, ILoggerHelper loggerHelper, ICmsSession cmsSession, IRepository<SysUser> userRepository, IUserService userService)
        {
            _auditLogRepository = auditLogRepository;
            _provider = provider;
            _unitOfWork = unitOfWor;
            _loggerHelper = loggerHelper;
            _cmsSession = cmsSession;
            _userService = userService;
        }
  

        /// <summary>
        /// 添加审计数据
        /// </summary>
        /// <param name="type"></param>
        /// <param name="method"></param>
        /// <param name="executionDuration"></param>
        /// <param name="arguments"></param>
        /// <param name="parameterFilter"></param>
        /// <param name="displayName"></param>
        /// <param name="exception"></param>
        /// <returns></returns>

        public async Task<OperationResult> AddAuditLogAsync(Type type, MethodInfo method, long? executionDuration, IDictionary<string, object> arguments, string parameterFilter = "", string displayName = "", Exception exception = null)
        {
            var userid = _cmsSession.GetUserId();
            if (exception.IsNotNull())
            {
                _loggerHelper.Error(type, exception);
            }
            //_unitOfWork.BeginTransaction();
            var auditDto = new AuditLogDto()
            {
                Id = Guid.NewGuid(),
                BrowserInfo = _provider.BrowserInfo,
                ClientIPAddress = _provider.ClientIpAddress,
                ClientName = _provider.ComputerName,
                UserId = userid,
                ServiceName = type != null ? type.FullName : string.Empty,
                MethodName = method.Name,
                Parameters = ConvertArgumentsToJson(arguments, parameterFilter),
                ExecutionTime = DateTime.Now,
                ExecutionDuration = executionDuration.Value,
                DisplayName = displayName,
                ExceptionInfo = exception.IsNull() ? null : exception.Message.Length <= 500 ? exception.Message:  $"【异常类型】：{type.FullName} \r\n【异常信息】：出现异常请查看日志",

            };
            var result = await _auditLogRepository.InsertAsync(auditDto);
            //_unitOfWork.Commit();
            return result;
        }

        /// <summary>
        /// 得到审计日志
        /// </summary>
        /// <param name="pageRequestData"></param>
        /// <returns></returns>

        public async Task<PageResult> GetAuditLogPageDataAsync(PageRequestData pageRequestData)
        {
            pageRequestData.NotNull(nameof(pageRequestData));

            if (!_cmsSession.GetUserId().IsEmptyOrNullOrHasValue() && !_cmsSession.IsAdministrators())
            {

                pageRequestData.Filters.Add(new FilterInfo
                {
                    Field = "UserId",
                    Value = _cmsSession.GetUserId()
                });
            }

            var filter = FilterHelp.ToFilterExpression<AuditLog>(pageRequestData.Filters);
            filter.NotNull(nameof(filter));
            pageRequestData.OrderBy = "ExecutionTime descending";
            var userList = _userService.Users;
            var query = await _auditLogRepository.QueryNotDelete.Where(filter).Join(userList,a=>a.UserId,u=>u.Id,(a,u)=>new {

                a.Id,
                a.UserId,
                a.ClientIPAddress,
                a.ClientName,
                a.BrowserInfo,
                a.DisplayName,
                a.ExecutionTime,
                a.ServiceName,
                a.MethodName,
                a.ExecutionDuration,
                UserName = u.UserName
            }).ToPageAsync(null,pageRequestData);
            return query.ToPageResult();
        }

        /// <summary>
        /// 把参数转换
        /// </summary>
        /// <param name="arguments"></param>
        /// <param name="parameterFilter"></param>
        /// <returns></returns>

        private string ConvertArgumentsToJson(IDictionary<string, object> arguments, string parameterFilter)
        {
            try
            {

                if (arguments?.Count == 0)
                {
                    return "{}";
                }
                if (!parameterFilter.IsNullOrWhiteSpace())
                {
                    var parmeterArr = parameterFilter.ToUpper().Split(",", true);
                    Dictionary<string, object> dic = new Dictionary<string, object>();
                    foreach (var item in arguments)
                    {
                        var vaelue = item.Value.ToString()?.Split(",", true)?.Where(o => parmeterArr.Contains(o.ToUpper())).ToJoin(",");
                        dic.Add(item.Key, vaelue);

                    }

                    return dic.ToJson();
                }

                return arguments.ToJson();
            }
            catch (Exception ex)
            {

                return "{}";
            }
        }


    }
}

